package library

///
// 数据库
///
import (
	"database/sql"
	"os"
	"sync"
	"time"

	// 数据库驱动
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/mattn/go-sqlite3"
)

var (
	// DataSheet 数据库表类型
	DataSheet map[string]string
)

func init() {
	DataSheet = make(map[string]string)
	// 日志表类型
	DataSheet["Log"] = `"Time" INTEGER(64),"Ttype" INTEGER,"Path" TEXT,"Data" TEXT`
	DataSheet["PProf"] = `"Time" INTEGER(64), "PProf" BLOB,"Trace" BLOB`
	DataSheet["Timeout"] = `"Time" INTEGER(64), "Memory" INTEGER(64), "Timeout" INTEGER(64), "TimeoutMax" INTEGER(1), "Value" TEXT, "CtackInformation" TEXT`
}

// Cache 数据库缓存
type Cache struct {
	db *sql.DB
	Tx *sql.Tx
	// 查询列表
	Stmt map[string]*sql.Stmt
	lock bool
	data bool
	// 锁
	rwmLock *sync.RWMutex
}

// Creation 创建缓存
func (C *Cache) Creation(db *sql.DB) error {
	if C.lock {
		return nil
	}
	var err error
	C.Tx, err = db.Begin()
	if err != nil {
		return err
	}
	// 初始化
	C.db = db
	C.Stmt = make(map[string]*sql.Stmt, 0)
	C.lock = true
	C.data = false
	C.rwmLock = new(sync.RWMutex)
	// 提交
	go func(C *Cache) {
		// 等待写
		for {
			<-time.After(time.Minute) // 每分钟提交一次日志
			if !C.lock {
				return
			}
			C.Commit()
		}
	}(C)
	return nil
}

// Add 处理
func (C *Cache) Add(name string, sql string) error {
	// 创建
	stmt, err := C.db.Prepare(sql)
	if err != nil {
		return err
	}
	C.Stmt[name] = stmt
	return nil
}

// Write 添加数据
func (C *Cache) Write(name string, value ...interface{}) error {
	if stmt, ok := C.Stmt[name]; ok {
		C.rwmLock.RLock()
		_, err := C.Tx.Stmt(stmt).Exec(value...)
		if err != nil {
			return err
		}
		C.rwmLock.RUnlock()
		C.data = true
	}
	return nil
}

// Close 关闭缓存
func (C *Cache) Close() error {
	// 设置关闭
	C.lock = false
	// 提交修改
	err := C.Tx.Commit()
	if err != nil {
		return err
	}
	// 关闭查询
	for _, S := range C.Stmt {
		S.Close()
	}
	// 关闭事务
	C.Tx.Rollback()
	return nil
}

// Commit 提交
func (C *Cache) Commit() error {
	// 写数据
	if C.data {
		C.data = false
		C.rwmLock.Lock()
		// 处理数据
		err := C.Tx.Commit()
		if err != nil {
			return err
		}
		// 关闭事务
		C.Tx.Rollback()
		// 重创事务
		C.Tx, err = C.db.Begin()
		if err != nil {
			return err
		}
		C.rwmLock.Unlock()
	}
	return nil
}

// DB 数据库类
type DB struct {
	Type string
	db   *sql.DB
}

// OpenFile 打开数据库文件
func (D *DB) OpenFile(file string) error {
	// 判断文件是否存在
	if ok := PathExists(file); !ok {
		// 创建文件
		f, err := os.Create(file)
		if err != nil {
			return err
		}
		f.Close()
	}
	// 打开数据库
	D.Open(file)
	return nil
}

// Open 打开数据
func (D *DB) Open(dataSourceName string) error {
	var err error // 错误处理
	// 打开数据库
	D.db, err = sql.Open(D.Type, dataSourceName)
	if err != nil {
		return err
	}
	return nil
}

// CreateTable 创建表
func (D *DB) CreateTable(Name string, Type string) error {
	if SQL, ok := DataSheet[Type]; ok {
		_, err := D.db.Exec(`CREATE TABLE IF NOT EXISTS "` + Name + `"(` + SQL + ");")
		if err != nil {
			return err
		}
	}
	return nil
}

// SetExec 添加表数据
func (D *DB) SetExec(sql string, value ...interface{}) (sql.Result, error) {
	stmt, err := D.db.Prepare(sql)
	defer stmt.Close()
	if err != nil {
		return nil, err
	}
	R, err := stmt.Exec(value...)
	if err != nil {
		return R, err
	}
	return nil, nil
}

// Close 关闭数据库
func (D *DB) Close() {
	D.db.Close()
}

// GetDB 获得DB
func (D *DB) GetDB() *sql.DB {
	return D.db
}

// GetCache 获得缓存
func (D *DB) GetCache() (C *Cache) {
	C = &Cache{}
	C.Creation(D.db)
	return
}
